1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package xmlkit;
26 import xmlkit.XMLKit.*;
27
28 import java.util.*;
29 import java.security.MessageDigest;
30 import java.nio.ByteBuffer;
31 import xmlkit.XMLKit.Element;
32
33
34
35 public abstract class ClassSyntax {
36
37 public interface GetCPIndex {
38
39 int getCPIndex(int tag, String name);
40 }
41 public static final int CONSTANT_Utf8 = 1,
42 CONSTANT_Integer = 3,
43 CONSTANT_Float = 4,
44 CONSTANT_Long = 5,
45 CONSTANT_Double = 6,
46 CONSTANT_Class = 7,
47 CONSTANT_String = 8,
48 CONSTANT_Fieldref = 9,
49 CONSTANT_Methodref = 10,
50 CONSTANT_InterfaceMethodref = 11,
51 CONSTANT_NameAndType = 12;
52 private static final String[] cpTagName = {
53 null,
54 "Utf8",
55 null,
56 "Integer",
57 "Float",
58 "Long",
59 "Double",
60 "Class",
61 "String",
62 "Fieldref",
63 "Methodref",
64 "InterfaceMethodref",
65 "NameAndType",
66 null
67 };
68 private static final Set<String> cpTagNames;
69
70 static {
71 Set<String> set = new HashSet<String>(Arrays.asList(cpTagName));
72 set.remove(null);
73 cpTagNames = Collections.unmodifiableSet(set);
74 }
75 public static final int ITEM_Top = 0,
76 ITEM_Integer = 1,
77 ITEM_Float = 2,
78 ITEM_Double = 3,
79 ITEM_Long = 4,
80 ITEM_Null = 5,
81 ITEM_UninitializedThis = 6,
82 ITEM_Object = 7,
83 ITEM_Uninitialized = 8,
84 ITEM_ReturnAddress = 9,
85 ITEM_LIMIT = 10;
86 private static final String[] itemTagName = {
87 "Top",
88 "Integer",
89 "Float",
90 "Double",
91 "Long",
92 "Null",
93 "UninitializedThis",
94 "Object",
95 "Uninitialized",
96 "ReturnAddress",};
97 private static final Set<String> itemTagNames;
98
99 static {
100 Set<String> set = new HashSet<String>(Arrays.asList(itemTagName));
101 set.remove(null);
102 itemTagNames = Collections.unmodifiableSet(set);
103 }
104 protected static final HashMap<String, String> attrTypesBacking;
105 protected static final Map<String, String> attrTypesInit;
106
107 static {
108 HashMap<String, String> at = new HashMap<String, String>();
109
110
111
112
113
114 at.put("Method.Bridge", "<Bridge>");
115 at.put("Method.Varargs", "<Varargs>");
116 at.put("Class.Enum", "<Enum>");
117 at.put("*.Signature", "<Signature>RSH");
118
119
120 at.put("Field.ConstantValue", "<ConstantValue>KQH");
121 at.put("Class.SourceFile", "<SourceFile>RUH");
122 at.put("Class.InnerClasses", "NH[<InnerClass><class=>RCH<outer=>RCH<name=>RUH<flags=>FH]");
123 at.put("Code.LineNumberTable", "NH[<LineNumber><bci=>PH<line=>H]");
124 at.put("Code.LocalVariableTable", "NH[<LocalVariable><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]");
125 at.put("Code.LocalVariableTypeTable", "NH[<LocalVariableType><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]");
126 at.put("Method.Exceptions", "NH[<Exception><name=>RCH]");
127 at.put("Method.Code", "<Code>...");
128 at.put("Code.StackMapTable", "<Frame>...");
129
130 if (true) {
131 at.put("Code.StackMapTable",
132 "[NH[<Frame>(1)]]"
133 + "[TB"
134 + "(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79"
135 + ",80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95"
136 + ",96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111"
137 + ",112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127"
138 + ")[<SameLocals1StackItemFrame>(4)]"
139 + "(247)[<SameLocals1StackItemExtended>H(4)]"
140 + "(248)[<Chop3>H]"
141 + "(249)[<Chop2>H]"
142 + "(250)[<Chop1>H]"
143 + "(251)[<SameFrameExtended>H]"
144 + "(252)[<Append1>H(4)]"
145 + "(253)[<Append2>H(4)(4)]"
146 + "(254)[<Append3>H(4)(4)(4)]"
147 + "(255)[<FullFrame>H(2)(3)]"
148 + "()[<SameFrame>]]"
149 + "[NH[<Local>(4)]]"
150 + "[NH[<Stack>(4)]]"
151 + "[TB"
152 + ("(0)[<Top>]"
153 + "(1)[<ItemInteger>](2)[<ItemFloat>](3)[<ItemDouble>](4)[<ItemLong>]"
154 + "(5)[<ItemNull>](6)[<ItemUninitializedThis>]"
155 + "(7)[<ItemObject><class=>RCH]"
156 + "(8)[<ItemUninitialized><bci=>PH]"
157 + "()[<ItemUnknown>]]"));
158 }
159
160 at.put("Class.EnclosingMethod", "<EnclosingMethod><class=>RCH<desc=>RDH");
161
162
163 String vpf = "[<RuntimeVisibleAnnotation>";
164 String ipf = "[<RuntimeInvisibleAnnotation>";
165 String apf = "[<Annotation>";
166 String mdanno2 = ""
167 + "<type=>RSHNH[<Member><name=>RUH(3)]]"
168 + ("[TB"
169 + "(\\B,\\C,\\I,\\S,\\Z)[<value=>KIH]"
170 + "(\\D)[<value=>KDH]"
171 + "(\\F)[<value=>KFH]"
172 + "(\\J)[<value=>KJH]"
173 + "(\\c)[<class=>RSH]"
174 + "(\\e)[<type=>RSH<name=>RUH]"
175 + "(\\s)[<String>RUH]"
176 + "(\\@)[(2)]"
177 + "(\\[)[NH[<Element>(3)]]"
178 + "()[]"
179 + "]");
180 String visanno = "[NH[(2)]][(1)]" + vpf + mdanno2;
181 String invanno = "[NH[(2)]][(1)]" + ipf + mdanno2;
182 String vparamanno = ""
183 + "[NB[<RuntimeVisibleParameterAnnotation>(1)]][NH[(2)]]"
184 + apf + mdanno2;
185 String iparamanno = ""
186 + "[NB[<RuntimeInvisibleParameterAnnotation>(1)]][NH[(2)]]"
187 + apf + mdanno2;
188 String mdannodef = "[<AnnotationDefault>(3)][(1)]" + apf + mdanno2;
189 String[] mdplaces = {"Class", "Field", "Method"};
190 for (String place : mdplaces) {
191 at.put(place + ".RuntimeVisibleAnnotations", visanno);
192 at.put(place + ".RuntimeInvisibleAnnotations", invanno);
193 }
194 at.put("Method.RuntimeVisibleParameterAnnotations", vparamanno);
195 at.put("Method.RuntimeInvisibleParameterAnnotations", iparamanno);
196 at.put("Method.AnnotationDefault", mdannodef);
197
198 attrTypesBacking = at;
199 attrTypesInit = Collections.unmodifiableMap(at);
200 }
201
202 ;
203 private static final String[] jcovAttrTypes = {
204 "Code.CoverageTable=NH[<Coverage><bci=>PH<type=>H<line=>I<pos=>I]",
205 "Code.CharacterRangeTable=NH[<CharacterRange><bci=>PH<endbci=>POH<from=>I<to=>I<flag=>H]",
206 "Class.SourceID=<SourceID><id=>RUH",
207 "Class.CompilationID=<CompilationID><id=>RUH"
208 };
209 protected static final String[][] modifierNames = {
210 {"public"},
211 {"private"},
212 {"protected"},
213 {"static"},
214 {"final"},
215 {"synchronized"},
216 {null, "volatile", "bridge"},
217 {null, "transient", "varargs"},
218 {null, null, "native"},
219 {"interface"},
220 {"abstract"},
221 {"strictfp"},
222 {"synthetic"},
223 {"annotation"},
224 {"enum"},};
225 protected static final String EIGHT_BIT_CHAR_ENCODING = "ISO8859_1";
226 protected static final String UTF8_ENCODING = "UTF8";
227
228 protected static final Set<String> nonAttrTags;
229
230 static {
231 HashSet<String> tagSet = new HashSet<String>();
232 Collections.addAll(tagSet, new String[]{
233 "ConstantPool",
234 "Class",
235 "Interface",
236 "Method",
237 "Field",
238 "Handler",
239 "Attribute",
240 "Bytes",
241 "Instructions"
242 });
243 nonAttrTags = Collections.unmodifiableSet(tagSet);
244 }
245
246
247 public static Set<String> nonAttrTags() {
248 return nonAttrTags;
249 }
250
251 public static String cpTagName(int t) {
252 t &= 0xFF;
253 String ts = null;
254 if (t < cpTagName.length) {
255 ts = cpTagName[t];
256 }
257 if (ts != null) {
258 return ts;
259 }
260 return ("UnknownTag" + (int) t).intern();
261 }
262
263 public static int cpTagValue(String name) {
264 for (int t = 0; t < cpTagName.length; t++) {
265 if (name.equals(cpTagName[t])) {
266 return t;
267 }
268 }
269 return 0;
270 }
271
272 public static String itemTagName(int t) {
273 t &= 0xFF;
274 String ts = null;
275 if (t < itemTagName.length) {
276 ts = itemTagName[t];
277 }
278 if (ts != null) {
279 return ts;
280 }
281 return ("UnknownItem" + (int) t).intern();
282 }
283
284 public static int itemTagValue(String name) {
285 for (int t = 0; t < itemTagName.length; t++) {
286 if (name.equals(itemTagName[t])) {
287 return t;
288 }
289 }
290 return -1;
291 }
292
293 public void addJcovAttrTypes() {
294 addAttrTypes(jcovAttrTypes);
295 }
296
297 protected Map<String, String> attrTypes = attrTypesInit;
298
299 public void addAttrType(String opt) {
300 int eqpos = opt.indexOf('=');
301 addAttrType(opt.substring(0, eqpos), opt.substring(eqpos + 1));
302 }
303
304 public void addAttrTypes(String[] opts) {
305 for (String opt : opts) {
306 addAttrType(opt);
307 }
308 }
309
310 private void checkAttr(String attr) {
311 if (!attr.startsWith("Class.")
312 && !attr.startsWith("Field.")
313 && !attr.startsWith("Method.")
314 && !attr.startsWith("Code.")
315 && !attr.startsWith("*.")) {
316 throw new IllegalArgumentException("attr name must start with 'Class.', etc.");
317 }
318 String uattr = attr.substring(attr.indexOf('.') + 1);
319 if (nonAttrTags.contains(uattr)) {
320 throw new IllegalArgumentException("attr name must not be one of " + nonAttrTags);
321 }
322 }
323
324 private void checkAttrs(Map<String, String> at) {
325 for (String attr : at.keySet()) {
326 checkAttr(attr);
327 }
328 }
329
330 private void modAttrs() {
331 if (attrTypes == attrTypesInit) {
332
333 attrTypes = new HashMap<String, String>(attrTypesBacking);
334 }
335 }
336
337 public void addAttrType(String attr, String fmt) {
338 checkAttr(attr);
339 modAttrs();
340 attrTypes.put(attr, fmt);
341 }
342
343 public void addAttrTypes(Map<String, String> at) {
344 checkAttrs(at);
345 modAttrs();
346 attrTypes.putAll(at);
347 }
348
349 public Map<String, String> getAttrTypes() {
350 if (attrTypes == attrTypesInit) {
351 return attrTypes;
352 }
353 return Collections.unmodifiableMap(attrTypes);
354 }
355
356 public void setAttrTypes(Map<String, String> at) {
357 checkAttrs(at);
358 modAttrs();
359 attrTypes.keySet().retainAll(at.keySet());
360 attrTypes.putAll(at);
361 }
362
363
364 protected static boolean matchTag(int tagValue, String caseStr) {
365
366 for (int pos = 0, max = caseStr.length(), comma;
367 pos < max;
368 pos = comma + 1) {
369 int caseValue;
370 if (caseStr.charAt(pos) == '\\') {
371 caseValue = caseStr.charAt(pos + 1);
372 comma = pos + 2;
373 assert (comma == max || caseStr.charAt(comma) == ',');
374 } else {
375 comma = caseStr.indexOf(',', pos);
376 if (comma < 0) {
377 comma = max;
378 }
379 caseValue = Integer.parseInt(caseStr.substring(pos, comma));
380 }
381 if (tagValue == caseValue) {
382 return true;
383 }
384 }
385 return false;
386 }
387
388 protected static String[] getBodies(String type) {
389 ArrayList<String> bodies = new ArrayList<String>();
390 for (int i = 0; i < type.length();) {
391 String body = getBody(type, i);
392 bodies.add(body);
393 i += body.length() + 2;
394 }
395 return bodies.toArray(new String[bodies.size()]);
396 }
397
398 protected static String getBody(String type, int i) {
399 assert (type.charAt(i) == '[');
400 int next = ++i;
401 for (int depth = 1; depth > 0; next++) {
402 switch (type.charAt(next)) {
403 case '[':
404 depth++;
405 break;
406 case ']':
407 depth--;
408 break;
409 case '(':
410 next = type.indexOf(')', next);
411 break;
412 case '<':
413 next = type.indexOf('>', next);
414 break;
415 }
416 assert (next > 0);
417 }
418 --next;
419 assert (type.charAt(next) == ']');
420 return type.substring(i, next);
421 }
422
423 public Element makeCPDigest(int length) {
424 MessageDigest md;
425 try {
426 md = MessageDigest.getInstance("MD5");
427 } catch (java.security.NoSuchAlgorithmException ee) {
428 throw new Error(ee);
429 }
430 int items = 0;
431 for (Element e : cpool.elements()) {
432 if (items == length) {
433 break;
434 }
435 if (cpTagNames.contains(e.getName())) {
436 items += 1;
437 md.update((byte) cpTagValue(e.getName()));
438 try {
439 md.update(e.getText().toString().getBytes(UTF8_ENCODING));
440 } catch (java.io.UnsupportedEncodingException ee) {
441 throw new Error(ee);
442 }
443 }
444 }
445 ByteBuffer bb = ByteBuffer.wrap(md.digest());
446 String l0 = Long.toHexString(bb.getLong(0));
447 String l1 = Long.toHexString(bb.getLong(8));
448 while (l0.length() < 16) {
449 l0 = "0" + l0;
450 }
451 while (l1.length() < 16) {
452 l1 = "0" + l1;
453 }
454 return new Element("Digest",
455 "length", "" + items,
456 "bytes", l0 + l1);
457 }
458
459 public Element getCPDigest(int length) {
460 if (length == -1) {
461 length = cpool.countAll(XMLKit.elementFilter(cpTagNames));
462 }
463 for (Element md : cpool.findAllElements("Digest").elements()) {
464 if (md.getAttrLong("length") == length) {
465 return md;
466 }
467 }
468 Element md = makeCPDigest(length);
469 cpool.add(md);
470 return md;
471 }
472
473 public Element getCPDigest() {
474 return getCPDigest(-1);
475 }
476
477 public boolean checkCPDigest(Element md) {
478 return md.equals(getCPDigest((int) md.getAttrLong("length")));
479 }
480
481 public static int computeInterfaceNum(String intMethRef) {
482 intMethRef = intMethRef.substring(1 + intMethRef.lastIndexOf(' '));
483 if (!intMethRef.startsWith("(")) {
484 return -1;
485 }
486 int signum = 1;
487 scanSig:
488 for (int i = 1; i < intMethRef.length(); i++) {
489 char ch = intMethRef.charAt(i);
490 signum++;
491 switch (ch) {
492 case ')':
493 --signum;
494 break scanSig;
495 case 'L':
496 i = intMethRef.indexOf(';', i);
497 break;
498 case '[':
499 while (ch == '[') {
500 ch = intMethRef.charAt(++i);
501 }
502 if (ch == 'L') {
503 i = intMethRef.indexOf(';', i);
504 }
505 break;
506 }
507 }
508 int num = (signum << 8) | 0;
509
510 return num;
511 }
512
513 protected Element cfile;
514 protected Element cpool;
515 protected Element klass;
516 protected Element currentMember;
517 protected Element currentCode;
518 }